package com.lianda.mutiple.example;

import java.util.concurrent.CompletableFuture;

//参考：https://www.jianshu.com/p/6f3ee90ab7d3/
//https://zhuanlan.zhihu.com/p/88321058
public class CompleteFutureMain {
    public static void main(String[] args) {
//        thenApply();
//        thenAccept();
//        thenRun();

//        thenCombine();
        thenAcceptBoth();
//        runAfterBoth();
//        applyToEither();

//        acceptEither();
//        exceptionally();

//        whenComplete();
//        handle();
    }

    /**
     *  主线程可能先与子线程结束，由于主线程要用到子线程的处理结果，但是此时子线程又没有执行完
     *  只好通过join()主线程等待子线程执行完毕再消亡。
     */
    // thenApply 的入参是上一个阶段的计算结果
    // 输出参数是： 经过Function函数转换后的结果
    public static void thenApply() {
        String result = CompletableFuture
                .supplyAsync(() -> "Hello")
                .thenApply(s -> s + " World").join();
        System.out.println(result);
    }


    // ThenAccept是对结果进行消耗，入参是Consumer，所以无返回值
    public static void thenAccept() {
        CompletableFuture.supplyAsync(() -> "Hello")
                .thenAccept(s -> System.out.println(s+" World"));
    }

    //对上一步计算结果不关心
    public static void thenRun(){
        CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello";
        }).thenRun(() -> System.out.println("hello world"));
        while (true){}
    }

    //结合两个CompletionStage的结果，进行转化后返回
    public static void thenCombine() {
        String result = CompletableFuture.supplyAsync(() ->{
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            return "hello";
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "world";
        }), (s1, s2) -> s1 + " " + s2).join();

        System.out.println(result);
    }

    //结合两个CompletionStage的结果，进行消耗，不返回值
    public static void thenAcceptBoth() {
        CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "f1 result";
        }).thenAcceptBoth(CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "f2 result";
        }), (s1, s2) -> System.out.println(s1 + "====" + s2));
        while (true){}
    }

    //不关心这两个CompletionStage的结果，只关心这两个CompletionStage执行完毕

    public static void runAfterBoth(){
        CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "s1";
        }).runAfterBothAsync(CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "s2";
        }), () -> System.out.println("hello world"));
        while (true){}
    }

    //两个CompletionStage，用计算较快的那一个
    public static void applyToEither() {
        String result = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "s1";
        }).applyToEither(CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello world";
        }), s -> s).join();
        System.out.println(result);
    }

    //两个CompletionStage，用计算较快的那一个
    public static void acceptEither() {
        CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "s1";
        }).acceptEither(CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello world";
        }), System.out::println);
        while (true){}
    }


    public static void exceptionally() {
        String result = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (1 == 1) {
                throw new RuntimeException("测试一下异常情况");
            }
            return "s1";
        }).exceptionally(e -> {
            System.out.println(e.getMessage());
            return "hello world";
        }).join();
        System.out.println(result);
    }

    public static void whenComplete() {
        String result = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (1 == 1) {
                throw new RuntimeException("测试一下异常情况");
            }
            return "s1";
        }).whenComplete((s, t) -> {
            System.out.println(s);
            System.out.println(t.getMessage());
        }).exceptionally(e -> {
            System.out.println(e.getMessage());
            return "hello world";
        }).join();
        System.out.println(result);
    }

    public static void handle() {
        String result = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //出现异常
            if (1 == 1) {
                throw new RuntimeException("测试一下异常情况");
            }
            return "s1";
        }).handle((s, t) -> {
            if (t != null) {
                return "hello world";
            }
            return s;
        }).join();
        System.out.println(result);
    }

}
